from collections.abc import Sequence
import os
from jinja2 import Environment, FileSystemLoader,Template,select_autoescape
from typing import List
from modules.code_genrator.models.gen_business_model import GenBusiness
from modules.code_genrator.models.gen_column_model import GenColumn
from modules.code_genrator.path_conf import JINJA_TEMPLATE_DIR
from config.config import settings


class CodeTemplate:
    def __init__(self) -> None:
        """ 初始化模板引擎 """
        self.env = Environment(
            loader=FileSystemLoader(JINJA_TEMPLATE_DIR),
            # 生成的是 Python 源码，不需要也不应该开启 HTML 自动转义
            autoescape=False,
            trim_blocks=True,
            lstrip_blocks=True,
            keep_trailing_newline=True,
            enable_async=True,
        )

        self.init_context = ''

        # 模板文件名到子目录的映射，以及子目录到文件后缀的映射
        # 例如：router.jinja -> routers 子目录 -> 文件名后缀 router
        self.TPL_TO_SUBDIR = {
            "router": "routers",
            "schema": "schemas",
            "params": "params",
            "model": "models",
            "service": "services",
            "vo": "vos",
            "curd": "curd",
        }
        self.SUBDIR_SUFFIX = {
            "routers": "router",
            "schemas": "schema",
            "params": "params",
            "models": "model",
            "services": "service",
            "vos": "vo",
            "curd": "curd",
        }

    def get_template(self, template_name: str) -> Template:
        """获取模板
        
        Args:
            template_name (str): 模板名称
        
        Returns:
            Template: 模板对象
        """
        
        return self.env.get_template(template_name)

    def get_template_files(self) -> List[str]:
        """获取所有模板文件
        
        Returns:
            List[str]: 模板文件列表
        """
        return [
            template for template in self.env.list_templates()
            if template.endswith('.jinja')
        ]

    @staticmethod
    def get_code_gen_paths(bussiness: GenBusiness) -> List[str]:
        """获取代码生成路径
        
        Args:
            bussiness (GenBusiness): 代码生成业务
        
        Returns:
            List[str]: 代码生成路径列表
        """
        # 使用英文安全模块名：若 app_name 含非 ASCII，则回退到 filename（由英文表名生成）
        app_name = bussiness.app_name if bussiness.app_name.isascii() else bussiness.filename
        filename = bussiness.filename

        base_path = bussiness.gen_path or f"app/modules/{app_name}"
        subdirs = [
            "routers",
            "schemas",
            "params",
            "models",
            "services",
            "vos",
            "curd",
        ]

        return [f"{base_path}/{sd}/{filename}_{CodeTemplate().SUBDIR_SUFFIX[sd]}.py" for sd in subdirs]
    
    def get_code_gen_path(self, business: GenBusiness, tpl_path: str) -> str:
        """获取代码生成路径
        
        Args:
            business (GenBusiness): 代码生成业务
            tpl_path (str): 模板路径
        
        Returns:
            str: 代码生成路径
        """
        # 根据模板文件名（不含扩展名）确定子目录与文件后缀，避免顺序依赖
        base_name = os.path.splitext(os.path.basename(tpl_path))[0]
        if base_name not in self.TPL_TO_SUBDIR:
            raise KeyError(f"未知模板文件名: {tpl_path}")

        # 使用英文安全模块名：若 app_name 含非 ASCII，则回退到 filename
        app_name = business.app_name if business.app_name.isascii() else business.filename
        filename = business.filename
        base_path = business.gen_path or f"app/modules/{app_name}"
        subdir = self.TPL_TO_SUBDIR[base_name]
        suffix = self.SUBDIR_SUFFIX[subdir]
        return f"{base_path}/{subdir}/{filename}_{suffix}.py"
    
    def get_vars(self, business: GenBusiness,models: Sequence[GenColumn]) -> dict[str, str | Sequence[GenColumn]]:
        """获取模板变量
        
        Args:
            business (GenBusiness): 代码生成业务
            models (Sequence[GenColumn]): 数据库模型序列
        
        Returns:
            dict: 模板变量
        """
        # 模板变量中的 app_name 也使用英文安全名，避免生成中文 import 路径
        return {
            'app_name': business.app_name if business.app_name.isascii() else business.filename,
            'table_name': business.table_name,
            'doc_comment': business.doc_comment,
            'table_comment': business.table_comment,
            'class_name': business.class_name,
            'schema_name': business.schema_name,
            'filename': business.filename,
            'default_datetime_column': business.default_datetime_column,
            'permission': str(business.table_name.replace('_', ':')),
            'database_type': settings.DATABASE_TYPE,
            'models': models,
            'model_types': [model.type for model in models],
        }
    
code_template : CodeTemplate = CodeTemplate()